import {
  BadRequestException,
  Injectable,
  InternalServerErrorException,
  Logger,
  Req,
} from '@nestjs/common';
import { CreateSpecialColumnDto } from './dto/create-special-column.dto';
import { UpdateSpecialColumnDto } from './dto/update-special-column.dto';
import { InjectRepository } from '@nestjs/typeorm';
import { In, Like, Not, Repository } from 'typeorm';
import { Article } from 'src/article/entities/article.entity';
import { ArticleColumnRelated } from 'src/article/entities/article-column-related.entity';
import { SpecialColumn } from './entities/special-column.entity';
import {
  removeUnnecessaryData,
  setCreatedUser,
  setUpdatedUser,
  setDeletedUser,
} from 'src/utils';
import { ListArticleColumnDto } from './dto/list-article-column.dto';
import { ArticleColumnInclusionDto } from './dto/article-column-inclusion.dto';

@Injectable()
export class SpecialColumnService {
  private logger = new Logger('SpecialColumnService');

  constructor(
    @InjectRepository(Article)
    private readonly articleRepository: Repository<Article>,
    @InjectRepository(ArticleColumnRelated)
    private readonly articleColumnRelatedRepository: Repository<ArticleColumnRelated>,
    @InjectRepository(SpecialColumn)
    private readonly specialColumnRepository: Repository<SpecialColumn>,
  ) {}

  // 新建专栏
  async create(createSpecialColumnDto: CreateSpecialColumnDto, @Req() req) {
    try {
      // 创建专栏实体
      const column = this.specialColumnRepository.create(
        createSpecialColumnDto,
      );
      const createdColumn = setCreatedUser(req, column);

      this.logger.log('@@@@ 新建专栏 createdColumn', createdColumn);

      return await this.specialColumnRepository.save(createdColumn);
    } catch (error) {
      this.logger.error('@@@@ 新建专栏失败:', error);
      throw new InternalServerErrorException('新建专栏失败');
    }
  }

  // 查询所有专栏
  async findAll() {
    try {
      const data = await this.specialColumnRepository.find({
        where: { isDeleted: 0 },
      });

      // 分别查询每个专栏的文章数量
      const specialColumnsWithCount = await Promise.all(
        data.map(async (column) => {
          const count = await this.articleColumnRelatedRepository.count({
            where: { columnId: column.id, isDeleted: 0 },
          });
          return { ...column, count };
        }),
      );

      const filterData = removeUnnecessaryData(specialColumnsWithCount);

      this.logger.log('@@@ 查询专栏列表', filterData);

      return filterData;
    } catch (error) {
      this.logger.error('@@@@ 查询专栏列表失败:', error);
      throw new InternalServerErrorException('查询专栏列表失败');
    }
  }

  // 查询专栏列表下拉选择
  async findAllForSelect() {
    try {
      const data = await this.specialColumnRepository.find({
        select: ['id', 'title'],
        where: { isDeleted: 0 },
      });

      this.logger.log('@@@ 查询专栏列表下拉选择', data);

      return data;
    } catch (error) {
      this.logger.error('@@@@ 查询专栏列表下拉选择失败:', error);
      throw new InternalServerErrorException('查询专栏列表下拉选择失败');
    }
  }

  // 查询专栏详情
  async findOne(id: number) {
    if (!id) {
      throw new BadRequestException('id必填');
    }
    try {
      const data = await this.specialColumnRepository.findOne({
        where: { id, isDeleted: 0 },
      });
      delete data.isDeleted;

      this.logger.log('@@@ 查询专栏详情', data);

      return data;
    } catch (error) {
      this.logger.error('@@@@ 查询专栏详情失败:', error);
      throw new InternalServerErrorException('查询专栏详情失败');
    }
  }

  // 修改专栏
  async update(
    id: number,
    updateSpecialColumnDto: UpdateSpecialColumnDto,
    @Req() req,
  ) {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    try {
      // 专栏实体
      const column = Object.assign(
        new UpdateSpecialColumnDto(),
        updateSpecialColumnDto,
      );
      const updatedColumn = setUpdatedUser(req, column);

      this.logger.log('@@@ 修改专栏 updatedColumn', updatedColumn);

      // 更新专栏表
      await this.specialColumnRepository.update(id, updatedColumn);

      // 更新文章专栏关联表
      const relations = await this.articleColumnRelatedRepository.find({
        where: { columnId: id },
      });

      for (const relation of relations) {
        relation.columnTitle = updateSpecialColumnDto.title;
        await this.articleColumnRelatedRepository.save(relation);
      }

      return { message: '修改成功' };
    } catch (error) {
      this.logger.error('@@@@ 修改专栏失败:', error);
      throw new InternalServerErrorException('修改专栏失败');
    }
  }

  // 软删除文章专栏关联表
  async softDeleteArticleColumnRelations(columnId: number) {
    const relations = await this.articleColumnRelatedRepository.find({
      where: { columnId, isDeleted: 0 },
    });

    for (const relation of relations) {
      relation.isDeleted = 1; // 标记为已删除
      await this.articleColumnRelatedRepository.save(relation);
    }
  }

  // 软删除单个专栏
  async softDeleteColumn(id: number, @Req() req) {
    if (!id) {
      throw new BadRequestException('id必填');
    }

    try {
      const column = new SpecialColumn();
      const removedColumn = setDeletedUser(req, column);

      this.logger.log('@@@ 软删除单个专栏 removedColumn', removedColumn);

      await this.specialColumnRepository.update(id, removedColumn);

      // 软删除文章专栏关联表
      await this.softDeleteArticleColumnRelations(id);

      return { message: '删除成功' };
    } catch (error) {
      this.logger.error('@@@@ 删除专栏失败:', error);
      throw new InternalServerErrorException('删除专栏失败');
    }
  }

  // 根据专栏id查询文章列表
  async queryArticleListByColumnId(id: number, query: ListArticleColumnDto) {
    if (!id) {
      throw new BadRequestException('专栏ID不能为空');
    }

    try {
      // 查询关联中间表对应的articleIds
      const articleIdsMap = await this.articleColumnRelatedRepository.find({
        select: ['articleId'],
        where: {
          columnId: id,
          isDeleted: 0,
        },
      });

      const articleIds = articleIdsMap.map((item) => item.articleId);

      // 分页查询文章表
      const [data, total] = await this.articleRepository.findAndCount({
        where: {
          id: In(articleIds),
          title: query.articleTitle ? Like(`%${query.articleTitle}%`) : null,
          isDeleted: 0,
        },
        order: {
          id: 'DESC',
        },
        skip: (query.pageNum - 1) * query.pageSize,
        take: query.pageSize,
      });

      return {
        list: removeUnnecessaryData(data),
        pageNum: Number(query.pageNum),
        pageSize: Number(query.pageSize),
        total,
      };
    } catch (error) {
      this.logger.error('@@@@ 根据专栏id查询文章列表:', error);
      throw new InternalServerErrorException('列表查询失败');
    }
  }

  // 查询非该专栏的文章列表
  async queryOtherArticleListByColumnId(
    id: number,
    query: ListArticleColumnDto,
  ) {
    if (!id) {
      throw new BadRequestException('专栏ID不能为空');
    }

    try {
      // 查询关联中间表对应的articleIds 取反逻辑
      const articleIdsMap = await this.articleColumnRelatedRepository.find({
        select: ['articleId'],
        where: {
          columnId: id,
          isDeleted: 0,
        },
      });

      const articleIds = articleIdsMap.map((item) => item.articleId);

      // 分页查询文章表
      const [data, total] = await this.articleRepository.findAndCount({
        where: {
          id: Not(In(articleIds)),
          title: query.articleTitle ? Like(`%${query.articleTitle}%`) : null,
          isDeleted: 0,
        },
        order: {
          id: 'DESC',
        },
        skip: (query.pageNum - 1) * query.pageSize,
        take: query.pageSize,
      });

      return {
        list: removeUnnecessaryData(data),
        pageNum: Number(query.pageNum),
        pageSize: Number(query.pageSize),
        total,
      };
    } catch (error) {
      this.logger.error('@@@@ 查询非该专栏的文章列表:', error);
      throw new InternalServerErrorException('列表查询失败');
    }
  }

  // 批量取消收录至该专栏
  async cancelArticleInclusion(body: ArticleColumnInclusionDto) {
    try {
      await this.articleColumnRelatedRepository.update(
        {
          columnId: body.columnId,
          articleId: In(body.articleIds),
        },
        {
          isDeleted: 1,
        },
      );

      return {
        message: '取消收录成功',
      };
    } catch (error) {
      this.logger.error('取消收录失败:', error);
      throw new InternalServerErrorException('取消收录失败');
    }
  }

  // 批量添加新的文章至专栏
  async batchAddNewInclusion(articleIds, columnId) {
    return await Promise.all(
      articleIds.map(async (articleId) => {
        const column = await this.specialColumnRepository.findOneBy({
          id: columnId,
        });
        const article = await this.articleRepository.findOneBy({
          id: articleId,
        });
        const newRelation = new ArticleColumnRelated();
        newRelation.articleId = articleId;
        newRelation.articleTitle = article.title;
        newRelation.columnId = columnId;
        newRelation.columnTitle = column.title;
        return await this.articleColumnRelatedRepository.save(newRelation);
      }),
    );
  }

  // 文章批量收录至该专栏
  async addArticleInclusion(body: ArticleColumnInclusionDto) {
    try {
      // 判断是否已经收录过了但被软删除过的
      const hasInclusionArticles =
        await this.articleColumnRelatedRepository.find({
          select: ['articleId'],
          where: {
            columnId: body.columnId,
          },
        });

      // 已经收录的文章ID
      const hasInclusionArticleIds = hasInclusionArticles.map(
        (item) => item.articleId,
      );

      // 判断收录的文章id，哪些是新的（执行添加），哪些是已经收录的（修改isDeleted）
      // 新添加的
      const newArticleIds = body.articleIds.filter(
        (id) => !hasInclusionArticleIds.includes(id),
      );

      const oldArticleIds = body.articleIds.filter((id) =>
        hasInclusionArticleIds.includes(id),
      );

      // 修改isDeleted为0
      await this.articleColumnRelatedRepository.update(
        {
          columnId: body.columnId,
          articleId: In(oldArticleIds),
        },
        {
          isDeleted: 0,
        },
      );

      // 添加新
      await this.batchAddNewInclusion(newArticleIds, body.columnId);

      return {
        message: '文章批量收录成功',
      };
    } catch (error) {
      this.logger.error('文章批量收录至该专栏失败:', error);
      throw new InternalServerErrorException('文章批量收录至该专栏失败');
    }
  }
}
